#include "widget.h"
#include "./ui_widget.h"
#include <QFileDialog>
#include <QLabel>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDesktopServices>
#include <QMessageBox>
#include <QGraphicsDropShadowEffect>
#include <QPropertyAnimation>
#include <QFrame>
#include <QDebug>
#include <QProcess>
#include <windows.h>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("Ventrue v1.0");
    this->setMinimumSize(vMinWidth, vMinHeight);

    // 设置全局窗口的渐变背景色 被注释掉的是另一种色系的布局，两种我都很喜欢
    //QString gradient = QString("background: qlineargradient(x1:0, y1:1, x2:1, y2:0, stop:0 rgb(109,70,236), stop:1 rgb(250,178,255));border: 2px solid rgb(57,57,67); border-radius: 20px;");
    QString gradient = QString("background: qlineargradient(x1:0, y1:1, x2:1, y2:0, stop:0 rgb(90,250,236), stop:1 rgb(80,90,250));border: 2px solid rgb(57,57,67); ");
    this->setStyleSheet(gradient);

    // 创建垂直布局作为全局布局
    mainLayout = new QHBoxLayout(this);

    // 创建左侧布局
    leftLayout = new QVBoxLayout();

    // 创建中间布局
    midLayout = new QVBoxLayout();

    // 创建右侧布局
    rightLayout = new QVBoxLayout();

    // 添加到主布局
    mainLayout->addLayout(leftLayout);
    mainLayout->addLayout(midLayout);
    mainLayout->addLayout(rightLayout);

    // 初始化按钮
    initButton();

    // 初始化midLayout布局
    vAddLine();

    // 创建侧边栏
    vSideBar = new QWidget(this);

    // 初始化侧边栏
    initSideBar();
}

void Widget::initSideBar(){

    // 获取主窗口的宽度和高度
    int vMainWidth = width();
    int vMainHeight = height();

    // 创建一个布局用于在侧边栏内部放置按钮
    QVBoxLayout* sidebarLayout = new QVBoxLayout(vSideBar);

    vSideBar->setFixedWidth(0.23 * vMainWidth); // 设置侧边栏的宽度为主窗口宽度的0.3倍
    vSideBar->setFixedHeight(vMainHeight); // 设置侧边栏的高度与主窗口一样
    vSideBar->setStyleSheet(vSideBarStyle); // 设置侧边栏的背景颜色

    /* 编者注：
     *  当需要在侧边栏新建按钮或其他组件时，
     *  需要确保其中的组件->setObjectName("Settings")，
     *  这样做是为了当打开侧边栏时，
     *  只有侧边栏的组件可以正常工作，
     *  主界面的组件都不能被点击或其他操作。
     *          Written By Ventrue 2023.10.22
     */

    // 创建在侧边栏内的按钮
    QPushButton* vSideGobackBtn = new QPushButton("Go Back", vSideBar);
    connect(vSideGobackBtn, &QPushButton::clicked, this, &Widget::vControlSidebar);

    vSideGobackBtn->setStyleSheet(vSideButtonStyle);
    vSideGobackBtn->setFixedSize(vButtonWidth * 2, vLineHeight);
    vSideGobackBtn->setObjectName("Settings");
//    vSideGobackBtn->move(10, 10);
    sidebarLayout->setAlignment(Qt::AlignCenter);
    vSetShadow(vSideGobackBtn,1);

    QPushButton* vSideSaveBtn = new QPushButton("Save States..", vSideBar);
    connect(vSideSaveBtn, &QPushButton::clicked, this, &Widget::vSaveStates);
    vSideSaveBtn->setStyleSheet(vSideButtonStyle);
    vSideSaveBtn->setFixedSize(vButtonWidth*2, vLineHeight);
    vSideSaveBtn->setObjectName("Settings");
    vSetShadow(vSideSaveBtn,1);
    sidebarLayout->addWidget(vSideSaveBtn);
    sidebarLayout->setAlignment(Qt::AlignCenter); // 设置侧边栏内按钮的位置

    QPushButton* vSideOpenBtn = new QPushButton("Open States..", vSideBar);
    connect(vSideOpenBtn, &QPushButton::clicked, this, &Widget::vOpenStates);
    vSideOpenBtn->setStyleSheet(vSideButtonStyle);
    vSideOpenBtn->setFixedSize(vButtonWidth*2, vLineHeight);
    vSideOpenBtn->setObjectName("Settings");
    vSetShadow(vSideOpenBtn,1);
    sidebarLayout->addWidget(vSideOpenBtn);
    sidebarLayout->setAlignment(Qt::AlignCenter); // 设置侧边栏内按钮的位置

    // 初始化侧边栏的状态（隐藏）
    vIsSidebarVisible = false;
    vSideBar->move(-vSideBar->width(), 0); // 移动侧边栏到窗口左侧，初始时隐藏

}

// 初始化全局按钮
void Widget::initButton(){
    mainLayout->setSpacing(0);

    addBtn = new QPushButton("Add");
    vSetStyle(addBtn);

    delBtn = new QPushButton("Delete");
    vSetStyle(delBtn);

    execBtn = new QPushButton("Exec");
    vSetStyle(execBtn);

    vSettingButton = new QPushButton("Settings");
    vSetStyle(vSettingButton);

    connect(addBtn,&QPushButton::clicked,this,&Widget::vAddLine);
    connect(delBtn,&QPushButton::clicked,this,&Widget::vDeleteLine);
    connect(execBtn,&QPushButton::clicked,this,&Widget::vExecuteFile);
    connect(vSettingButton, &QPushButton::clicked, this, &Widget::vControlSidebar);

    leftLayout->addWidget(vSettingButton);
    rightLayout->addWidget(execBtn);
}

// 设置组件的阴影效果
void Widget::vSetShadow(QWidget* widget,int windowNum){

    QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(widget);
    if(windowNum == 0){ // 0是按钮和LineEdit的设置
        shadowEffect->setBlurRadius(60); // 模糊半径
        shadowEffect->setColor(QColor(56, 56, 68, 245)); // 阴影颜色和透明度
        widget->setGraphicsEffect(shadowEffect);
    }
    else if(windowNum == 1){ // 1是侧边栏的设置
        shadowEffect->setBlurRadius(90); // 模糊半径
        shadowEffect->setColor(QColor(107, 152, 250, 150)); // 阴影颜色和透明度
        widget->setGraphicsEffect(shadowEffect);
    }
    else if(windowNum == -1){// -1是取消阴影设置
        shadowEffect->setColor(QColor(216, 216, 216, 0)); // 阴影颜色和透明度
        widget->setGraphicsEffect(shadowEffect);
    }
}

// 从文件选择框选择文件并打印输出到对应行LineEdit的函数
void Widget::vFindPath(){
    QString fileName = QFileDialog::getOpenFileName(this, "请选择要执行的文件名称", "./");

    if (fileName.isEmpty()) {// 为空，说明没选择文件，要提醒
        QMessageBox msgBox;
        msgBox.setWindowTitle("Please Check !!");
        msgBox.setText("你没有选择要执行的文件...");
        msgBox.exec();
    }
    else{// 不为空，说明选择了一个文件
        // 区分是哪个Button触发的该槽函数
        QPushButton *whichBtn = qobject_cast<QPushButton *>(sender());
        if (whichBtn) {
            bool isOk;
            // 通过按钮的objectName属性来区分不同按钮
            int vBtnNum = whichBtn->objectName().toInt(&isOk);
            if (isOk) {
                // 转换成功
                vLineEdit[vBtnNum]->setText(fileName);
                vLineEdit[vBtnNum]->setStyleSheet(vLineEditStyle);
                vFileNames[vBtnNum] = fileName;
                qDebug()<<"vFileNames[" + QString::number(vBtnNum) + "] = " + vFileNames[vBtnNum];
            } else {
                // 转换失败
                qDebug() << "转换失败，无法识别是哪个按钮传递的信号";
            }
        }
    }
}

// 增加一个布局或者初始化布局的函数
void Widget::vAddLine(){
    vFileNum++;
    // 建立一个水平布局
    QHBoxLayout* vLayout = new QHBoxLayout();

    QPushButton* findBtn = new QPushButton("Find File..");
    vSetStyle(findBtn);

    QLineEdit* lineEdit = new QLineEdit;
    vSetStyle(lineEdit);

    connect(findBtn,&QPushButton::clicked,this,&Widget::vFindPath);

    if(vFileNum > 0){
        vLayouts[ vFileNum - 1 ]->removeWidget(addBtn);
        vLayouts[ vFileNum - 1 ]->removeWidget(delBtn);
    }

    vLayout->addWidget(findBtn);
    vLayout->addWidget(lineEdit);
    vLayout->addWidget(addBtn);
    vLayout->addWidget(delBtn);
    vLayout->setSpacing(10);

//    vLayout->setSpacing(20);
    vLayout->setAlignment(Qt::AlignCenter);
    //设置 vLayout 距离页面最高处的距离/距离页面左右两端都有20的距离
    vLayout->setContentsMargins(20, 10, 20, 0);
    midLayout->addLayout(vLayout);
    vLayouts[vFileNum] = vLayout;
}

// 删除行内所有元素，并将Add和Del按钮移位
void Widget::vDeleteLine() {
    if (vFileNum > 0) {
        // 获取当前要删除的布局
        QHBoxLayout* layoutToRemove = vLayouts[vFileNum];
        // 如果布局不为空，删除它
        if (layoutToRemove) {
            vLayouts[ vFileNum - 1 ]->addWidget(addBtn);
            vLayouts[ vFileNum - 1 ]->addWidget(delBtn);
            layoutToRemove->removeWidget(addBtn);
            layoutToRemove->removeWidget(delBtn);
            // 从 midLayout 中移除要删除的布局
            midLayout->removeItem(layoutToRemove);
            // 删除布局内的元素
            for (int i = 0; i < layoutToRemove->count(); ++i) {
                QWidget* widget = layoutToRemove->itemAt(i)->widget();
                if (widget) {
                    // 如果是 QLineEdit，需要清空相应的数据
                    if (qobject_cast<QLineEdit*>(widget)) {
                        vLineEdit[vFileNum]->clear();
                        vFileNames[vFileNum]="";
                        delete widget;
                    }
                    // 如果是 findBtn，删除它
                    if (qobject_cast<QPushButton*>(widget)) {
                        delete widget;
                    }
                }
            }
            // 删除布局
            delete layoutToRemove;
            // 减少 vFileNum 的值
        vFileNum--;
        }
    }
}

// 设置界面中的Button和LineEdit的样式
void Widget::vSetStyle(QWidget* widget) {

    // 公用的阴影效果对象
    vSetShadow(widget,0);
    // 设置名称，区分是哪一行的Button和LineEdit
    widget->setObjectName(QString::number(vFileNum));

    // 根据 widget 类型设置样式和最小尺寸
    if (qobject_cast<QPushButton*>(widget)) {
        // 如果是 QPushButton，添加特定的样式
        QPushButton* button = qobject_cast<QPushButton*>(widget);
        button->setFixedSize(vButtonWidth, vLineHeight);
        button->setStyleSheet(vBtnStyle);
    } else if (qobject_cast<QLineEdit*>(widget)) {
        // 如果是 QLineEdit，添加特定的样式
        QLineEdit* lineEdit = qobject_cast<QLineEdit*>(widget);
        lineEdit->setStyleSheet(vLineEditStyle);
        lineEdit->setMinimumSize(vMinLineEditWidth, vLineHeight);
        lineEdit->setMaximumSize(vMaxLineEditWidth,vLineHeight);
        //lineEdit->setFixedSize(200, vLineHeight);

        vLineEdit[vFileNum] = lineEdit; // 将 lineEdit 存入数组
    }
}

// 执行当前所需要打开的所有文件
void Widget::vExecuteFile(){
    SHELLEXECUTEINFO info = {0};
    info.cbSize = sizeof(SHELLEXECUTEINFO);
    info.fMask = SEE_MASK_NOCLOSEPROCESS;
    info.lpVerb = L"runas"; // 请求管理员权限
    info.nShow = SW_NORMAL; // 或者 SW_HIDE，取决于你是否想显示窗口

    for(int currentNum = 0 ; currentNum <= vFileNum ; currentNum++){
        QString currnetFileName= vFileNames[currentNum];
        qDebug()<< "第" + QString::number(currentNum+1) + "行,内容是: "+vFileNames[currentNum];
        QFileInfo fileInfo(currnetFileName);

        if (fileInfo.suffix().toLower() == "txt") {
        info.lpFile = L"notepad.exe"; // 使用记事本
        }
        else if (currnetFileName.contains("://")) {
            // 处理自定义协议链接（一般用不到）
            QString url = currnetFileName;
            QUrl launchUrl(url);
            QDesktopServices::openUrl(launchUrl);
        }
        else {
            // 放入支持的扩展名
            QStringList supportedExtensions;
            supportedExtensions << "docx" << "doc" << "pptx" << "ppt"<< "xlsx" << "xls";

            // 获取文件扩展名
            QString fileExtension = fileInfo.suffix().toLower();

            // 检查扩展名是否在支持的列表中
            if (supportedExtensions.contains(fileExtension)) {
                QString url = "file:///" + currnetFileName; // 注意添加file:///前缀
                QUrl launchUrl(url);
                QDesktopServices::openUrl(launchUrl);
            }else{
                // 处理其他文件类型
                info.lpFile = reinterpret_cast<LPCWSTR>(currnetFileName.utf16());
            }

        }

        if (ShellExecuteEx(&info) == TRUE) { // 执行成功
        vLineEdit[currentNum]->setStyleSheet(vSucceedLineStyle);
        } else { // 执行失败
        DWORD error = GetLastError();
        qDebug()<< error;
        vLineEdit[currentNum]->setStyleSheet(vFailedLineStyle);
        }
    }
}

void Widget::vOpenStates() {
    // 默认打开路径为当前路径下的resources文件夹
    QDir currentDir = QDir::current();
    QDir resourcesDir = currentDir.filePath("resources");
    QString defaultPath = resourcesDir.absolutePath(); // 获取绝对路径

    // 打开文件对话框，允许用户选择要打开的.ventrue文件
    QString filePath = QFileDialog::getOpenFileName(this, "Open States File", defaultPath, "Ventrue Files (*.ventrue)");

    // 检查用户是否取消了文件选择
    if (filePath.isEmpty()) {
        return;
    }

    QFile file(filePath);

    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file);
        QString stateLineNumStr = in.readLine(); // 读取第一行数据
        int realLineNum = 0;
        bool isOk = false;
        int stateLineNum = stateLineNumStr.toInt(&isOk);

        // 因为vFileNum随着我们Add或者Del而改变，因此用一个变量承载这个初始值
        int tempFileNum = vFileNum;
        if (isOk) {
            // 判断执行什么函数，执行几次,此时还不管vFileNames[]里面的内容
            if ((tempFileNum + 1) < stateLineNum) {
                for(int i=1;i<=stateLineNum-tempFileNum-1;i++){
                    vAddLine();
                    qDebug()<<"vAddLine";
                }
                vSideBar->raise();
                vSetWidgetEnabled(false);
            }
            else if ((tempFileNum + 1) > stateLineNum){
                for(int i=1;i<=tempFileNum+1-stateLineNum;i++){
                    vDeleteLine();
                    qDebug()<<"vDeleteLine";
                }
            }

            // vFileNames[]和vLineEdit[].text()内容填充
            while (!in.atEnd()) {
                QString line = in.readLine();
                if(realLineNum < stateLineNum){
                    vFileNames[realLineNum] = line;
                    vLineEdit[realLineNum]->setText(line);
                    qDebug()<<line;
                }
                realLineNum++;
            }
            file.close();
        }
    }
    QMessageBox msgBox;
    msgBox.setWindowTitle("Open Successful");
    msgBox.setText("File opened successfully!");
    msgBox.setStyleSheet(vMsgStyle);
    msgBox.exec();
}



void Widget::vSaveStates() {
    // 默认保存路径为当前路径下的resources文件夹
    QDir currentDir = QDir::current(); // 获取当前工作目录
    QDir resourcesDir = currentDir.filePath("resources"); // 将"resources"拼接到当前目录
    QString defaultPath = resourcesDir.absolutePath(); // 获取绝对路径

    // 打开文件对话框，允许用户选择文件路径和输入文件名
    QString filePath = QFileDialog::getSaveFileName(this, "Save States File", defaultPath, "Ventrue Files (*.ventrue)");

    // 检查用户是否取消了文件选择
    if (filePath.isEmpty()) {
        return;
    }

    QFile file(filePath);

    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream out(&file);

        out << vFileNum + 1 << "\n";
        for (int num = 0; num <= vFileNum; num++) {
        out << vFileNames[num] << "\n";
        }

        file.close();
    }
    QMessageBox msgBox;
    msgBox.setWindowTitle("Save Successful");
    msgBox.setText("File saved successfully!");
    msgBox.setStyleSheet(vMsgStyle);
    msgBox.exec();
}

void Widget::vControlSidebar(){
    vSideBar->raise(); // 将侧边栏置于最上层
    QPropertyAnimation* animation = new QPropertyAnimation(vSideBar, "pos");
    animation->setDuration(500); // 动画持续时间（毫秒）

    if (vIsSidebarVisible) {
        // 隐藏侧边栏
        animation->setStartValue(vSideBar->pos());
        animation->setEndValue(QPoint(-vSideBar->width(), 0));
        // 启用主窗口上的控件
        vSetWidgetEnabled(true);
        vSetShadow(vSideBar,-1);
    } else {
        // 显示侧边栏
        animation->setStartValue(vSideBar->pos());
        animation->setEndValue(QPoint(0, 0));
        // 禁用主窗口上的控件
        vSetWidgetEnabled(false);
        vSetShadow(vSideBar,1);
    }
    animation->start(); // 启动动画
    vIsSidebarVisible = !vIsSidebarVisible; // 切换侧边栏的状态
}

// 使得侧边栏打开时，只有侧边栏的功能能用，主界面的按钮被禁用
void Widget::vSetWidgetEnabled(bool enabled) {
    for (QWidget* widget : this->findChildren<QWidget*>()) {
        if (!(widget == vSideBar || widget->objectName() == "Settings")) { // 排除侧边栏内的子部件
            widget->setEnabled(enabled);
        }
    }
}

Widget::~Widget()
{
    delete ui;
}
